-- dcache wrapper
-- this is provided for a place holder until you do the cache labs
-- until then you should just place this file between your memory stage
-- of your pipeline and your priority mux for main memory.
library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.typeDefinitions.all;

entity dcache is
  port(
    clk      : in  std_logic;
    nReset   : in  std_logic;
    halt     : in  std_logic;
    halt_out : out std_logic;

    dMemRead      : in  std_logic;                       -- CPU side
    dMemWrite     : in  std_logic;                       -- CPU side
    dMemWait      : out std_logic;                       -- CPU side
    dMemAddr      : in  std_logic_vector (31 downto 0);  -- CPU side
    dMemDataRead  : out std_logic_vector (31 downto 0);  -- CPU side
    dMemDataWrite : in  std_logic_vector (31 downto 0);  -- CPU side

    adMemRead      : out std_logic;                       -- arbitrator side
    adMemWrite     : out std_logic;                       -- arbitrator side
    adMemWait      : in  std_logic;                       -- arbitrator side
    adMemAddr      : out std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataRead  : in  std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataWrite : out std_logic_vector (31 downto 0);   -- arbitrator side

    --bus side
    TxBusOp   : out memBusOp;
    TxBusAddr : out std_logic_vector(31 downto 0);
    TxBusResp : out memBusResp;
    TxBusData : out std_logic_vector(63 downto 0);
    RxBusOp   : in  memBusOp;
    RxBusAddr : in  std_logic_vector(31 downto 0);
    RxBusResp : in  memBusResp;
    RxBusData : in  std_logic_vector(63 downto 0);

		-- coco override
		cocoOverride	: in std_logic

    );

end dcache;

architecture struct of dcache is


  component dcache_ctrl port(
    clk, nReset                : in  std_logic;
    halt                       : in  std_logic;
    halt_out                   : out std_logic;
    -- CPU side
    dmemREN, dmemWEN           : in  std_logic;
    dmemAddr                   : in  std_logic_vector(31 downto 0);
    dmemWriteData              : in  std_logic_vector(31 downto 0);
    dmemReadData               : out std_logic_vector(31 downto 0);
    dmemWait                   : out std_logic;
    -- Arbiter side
    arbREN                     : out std_logic;  -- dcache read request
    arbWEN                     : out std_logic;  -- dcache write request
    arbWait                    : in  std_logic;  -- dcache must wait if 1
    arbAddr                    : out std_logic_vector(31 downto 0);  -- dcache address being read
    arbReadData                : in  std_logic_vector(31 downto 0);  -- dcache data to be read
    arbWriteData               : out std_logic_vector(31 downto 0);  -- dcache data to be written
    -- dcache side (sets 1 and 2)
    s1_tag, s2_tag             : out std_logic_vector(24 downto 0);
    s1_tagOut, s2_tagOut       : in  std_logic_vector(24 downto 0);
    s1_index, s2_index         : out std_logic_vector(3 downto 0);
    s1_wdat, s2_wdat           : out std_logic_vector(63 downto 0);  -- write data to be written on datWEN
    s1_wDirty, s2_wDirty       : out std_logic;  -- dirty bit to be written on datWEN
    s1_datWEN, s2_datWEN       : out std_logic;
    s1_rdat, s2_rdat           : in  std_logic_vector(63 downto 0);
    s1_rHit, s2_rHit           : in  std_logic;
    s1_rDirty, s2_rDirty       : in  std_logic;
    s1_rRecent, s2_rRecent     : in  std_logic;
    s1_wRecent, s2_wRecent     : out std_logic;
    s1_recentWEN, s2_recentWEN : out std_logic;
    -- dcache coherence
    s1_rMSI, s2_rMSI           : in  coherenceState;
    s1_busrMSI, s2_busrMSI     : in  coherenceState;
    s1_wMSI, s2_wMSI           : out coherenceState;
    s1_buswMSI, s2_buswMSI     : out coherenceState;
    s1_MSIWEN, s2_MSIWEN       : out std_logic;
    s1_busMSIWEN, s2_busMSIWEN : out std_logic;
    s1_busHit, s2_busHit       : in  std_logic;
    s1_busDirty, s2_busDirty   : in  std_logic;
    s1_busrdat, s2_busrdat     : in  std_logic_vector(63 downto 0);
    s1_busTag, s2_busTag       : out std_logic_vector(24 downto 0);
    s1_busIndex, s2_busIndex   : out std_logic_vector(3 downto 0);
    -- bus side (coherence signals)
    TxBusOp                    : out memBusOp;
    TxBusAddr                  : out std_logic_vector(31 downto 0);
    TxBusResp                  : out memBusResp;
    TxBusData                  : out std_logic_vector(63 downto 0);
    RxBusOp                    : in  memBusOp;
    RxBusAddr                  : in  std_logic_vector(31 downto 0);
    RxBusResp                  : in  memBusResp;
    RxBusData                  : in  std_logic_vector(63 downto 0);
    
    cocoOverride								: in std_logic
    );
  end component;



  
  component dcacheSet port(
    clk, nrst   : in  std_logic;
    tag_in1     : in  std_logic_vector(24 downto 0);
    data_in     : in  std_logic_vector(63 downto 0);
    index_in1   : in  std_logic_vector(3 downto 0);
    tag_in2     : in  std_logic_vector(24 downto 0);
    index_in2   : in  std_logic_vector(3 downto 0);
    cohere_in1  : in  coherenceState;
    cohere_in2  : in  coherenceState;
    cohere_wen1 : in  std_logic;
    cohere_wen2 : in  std_logic;
    recent_in   : in  std_logic;
    dirty_in    : in  std_logic;
    recent_wen  : in  std_logic;
    data_wen    : in  std_logic;
    data_out1   : out std_logic_vector(63 downto 0);
    data_out2   : out std_logic_vector(63 downto 0);
    tag_out     : out std_logic_vector(24 downto 0);
    hit1        : out std_logic;
    hit2        : out std_logic;
    cohere_out1 : out coherenceState;
    dirty1      : out std_logic;
    cohere_out2 : out coherenceState;
    dirty2      : out std_logic;
    multWrite   : out std_logic;
    recent      : out std_logic);
  end component;

  signal s1Cntrl, s2Cntrl : dcacheSetCntrl;
  
begin

  cntrl_c : dcache_ctrl port map (
    clk           => clk,
    nReset        => nReset,
    halt          => halt,
    dmemREN       => dMemRead,
    dmemWEN       => dMemWrite,
    dmemAddr      => dMemAddr,
    dmemWriteData => dMemDataWrite,
    dmemReadData  => dMemDataRead,
    dmemWait      => dMemWait,
    arbREN        => adMemRead,
    arbWEN        => adMemWrite,
    arbWait       => adMemWait,
    arbAddr       => adMemAddr,
    arbReadData   => adMemDataRead,
    arbWriteData  => adMemDataWrite,

    s1_tag       => s1Cntrl.tag_in1,
    s1_tagOut    => s1Cntrl.tag_out,
    s1_index     => s1Cntrl.index_in1,
    s1_wdat      => s1Cntrl.data_in,
    s1_rdat      => s1Cntrl.data_out1,
    s1_wDirty    => s1Cntrl.dirty_in,
    s1_rDirty    => s1Cntrl.dirty1,
    s1_wRecent   => s1Cntrl.recent_in,
    s1_rRecent   => s1Cntrl.recent,
    s1_datWEN    => s1Cntrl.data_wen,
    s1_recentWEN => s1Cntrl.recent_wen,
    s1_rHit      => s1Cntrl.hit1,

    s1_rMSI      => s1Cntrl.cohere_out1,
    s1_busrMSI   => s1Cntrl.cohere_out2,
    s1_wMSI      => s1Cntrl.cohere_in1,
    s1_buswMSI   => s1Cntrl.cohere_in2,
    s1_MSIWEN    => s1Cntrl.cohere_wen1,
    s1_busMSIWEN => s1Cntrl.cohere_wen2,
    s1_busHit    => s1Cntrl.hit2,
    s1_busDirty  => s1Cntrl.dirty2,
    s1_busrdat   => s1Cntrl.data_out2,
    s1_busTag    => s1Cntrl.tag_in2,
    s1_busIndex  => s1Cntrl.index_in2,

    s2_tag       => s2Cntrl.tag_in1,
    s2_tagOut    => s2Cntrl.tag_out,
    s2_index     => s2Cntrl.index_in1,
    s2_wdat      => s2Cntrl.data_in,
    s2_rdat      => s2Cntrl.data_out1,
    s2_wDirty    => s2Cntrl.dirty_in,
    s2_rDirty    => s2Cntrl.dirty1,
    s2_wRecent   => s2Cntrl.recent_in,
    s2_rRecent   => s2Cntrl.recent,
    s2_datWEN    => s2Cntrl.data_wen,
    s2_recentWEN => s2Cntrl.recent_wen,
    s2_rHit      => s2Cntrl.hit1,

    s2_rMSI      => s2Cntrl.cohere_out1,
    s2_busrMSI   => s2Cntrl.cohere_out2,
    s2_wMSI      => s2Cntrl.cohere_in1,
    s2_buswMSI   => s2Cntrl.cohere_in2,
    s2_MSIWEN    => s2Cntrl.cohere_wen1,
    s2_busMSIWEN => s2Cntrl.cohere_wen2,
    s2_busHit    => s2Cntrl.hit2,
    s2_busDirty  => s2Cntrl.dirty2,
    s2_busrdat   => s2Cntrl.data_out2,
    s2_busTag    => s2Cntrl.tag_in2,
    s2_busIndex  => s2Cntrl.index_in2,

    TxBusOp   => TxBusOp,
    TxBusAddr => TxBusAddr,
    TxBusResp => TxBusResp,
    TxBusData => TxBusData,
    RxBusOp   => RxBusOp,
    RxBusAddr => RxBusAddr,
    RxBusResp => RxBusResp,
    RxBusData => RxBusData,

    halt_out => halt_out,
    
    cocoOverride => cocoOverride);

  s1Cntrl.clk  <= clk;
  s2Cntrl.clk  <= clk;
  s1Cntrl.nrst <= nReset;
  s2Cntrl.nrst <= nReset;

  s1_c : dcacheSet port map (
    clk       => s1Cntrl.clk,
    nrst      => s1Cntrl.nrst,
    tag_in1   => s1Cntrl.tag_in1,
    data_in   => s1Cntrl.data_in,
    index_in1 => s1Cntrl.index_in1,

    tag_in2   => s1Cntrl.tag_in2,
    index_in2 => s1Cntrl.index_in2,

    cohere_in1  => s1Cntrl.cohere_in1,
    cohere_in2  => s1Cntrl.cohere_in2,
    cohere_wen1 => s1Cntrl.cohere_wen1,
    cohere_wen2 => s1Cntrl.cohere_wen2,

    recent_in  => s1Cntrl.recent_in,
    dirty_in   => s1Cntrl.dirty_in,
    recent_wen => s1Cntrl.recent_wen,
    data_wen   => s1Cntrl.data_wen,

    data_out1 => s1Cntrl.data_out1,
    data_out2 => s1Cntrl.data_out2,
    tag_out   => s1Cntrl.tag_out,

    hit1 => s1Cntrl.hit1,
    hit2 => s1Cntrl.hit2,

    multWrite => s1Cntrl.multWrite,

    cohere_out1 => s1Cntrl.cohere_out1,
    cohere_out2 => s1Cntrl.cohere_out2,

    dirty1 => s1Cntrl.dirty1,
    dirty2 => s1Cntrl.dirty2,
    recent => s1Cntrl.recent);

  s2_c : dcacheSet port map (
    clk       => s2Cntrl.clk,
    nrst      => s2Cntrl.nrst,
    tag_in1   => s2Cntrl.tag_in1,
    data_in   => s2Cntrl.data_in,
    index_in1 => s2Cntrl.index_in1,

    tag_in2   => s2Cntrl.tag_in2,
    index_in2 => s2Cntrl.index_in2,

    cohere_in1  => s2Cntrl.cohere_in1,
    cohere_in2  => s2Cntrl.cohere_in2,
    cohere_wen1 => s2Cntrl.cohere_wen1,
    cohere_wen2 => s2Cntrl.cohere_wen2,

    recent_in  => s2Cntrl.recent_in,
    dirty_in   => s2Cntrl.dirty_in,
    recent_wen => s2Cntrl.recent_wen,
    data_wen   => s2Cntrl.data_wen,

    data_out1 => s2Cntrl.data_out1,
    data_out2 => s2Cntrl.data_out2,
    tag_out   => s2Cntrl.tag_out,

    hit1 => s2Cntrl.hit1,
    hit2 => s2Cntrl.hit2,

    multWrite => s2Cntrl.multWrite,

    cohere_out1 => s2Cntrl.cohere_out1,
    cohere_out2 => s2Cntrl.cohere_out2,

    dirty1 => s2Cntrl.dirty1,
    dirty2 => s2Cntrl.dirty2,
    recent => s2Cntrl.recent);



end struct;
